﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Encog.ML.Data;
using Encog.ML.Data.Basic;
using Encog.ML.Data.Market;
using Encog.ML.Data.Market.Loader;
using Encog.Neural.Data.Basic;
using Encog.Neural.NeuralData;
using System.Windows.Forms;

namespace IntObl
{
    public class Utils
    {
       // próg, od którego traktujemy trend jako spadkowy
        public double BearPercent { get; set; }

        // próg, od którego traktujemy trend jako rosnący
        public double BullPercent { get; set; }

   
        public int EvalWindow { get; set; }
        public int PredictWindow { get; set; }     
      
        /// <summary>
        /// tworzy dane na wejście sieci.
        /// </summary>
        /// <param name="marketData"></param>
        /// <param name="marketDataIndex"></param>
        /// <returns></returns>
        public INeuralData CreateData(
        List<LoadedMarketData> marketData,
        int marketDataIndex)
        {
            INeuralData neuralData = new BasicNeuralData(14);
            int totalPatterns = 0;

            // licznik zliczeń poszczególnych wzorców
            int[] patternCount = new int[14];

            for (int i = 0; i < EvalWindow; i++)
            {
                LoadedMarketData data = marketData[(marketDataIndex - EvalWindow) + i];

                IdentifyCandleStick candle = new IdentifyCandleStick();
                candle.SetStats(data);
                int pattern = candle.DeterminePattern();
                if (pattern != IdentifyCandleStick.UNKNOWN)
                {
                    totalPatterns++;
                     patternCount[pattern]++;
                }
            }

            if (totalPatterns == 0)
                return null;

            for (int i = 0; i < 14; i++)
            {
                neuralData[i] = ((double)patternCount[i]) / ((double)totalPatterns);
            }

            return neuralData;
        }


        /// <summary>
        /// utworzenie pary treningowej, zawierającej informację czy w danym dniu
        /// był wzrost czy spadek
        /// </summary>
        /// <param name="data"></param>
        /// <param name="index"></param>
        /// <param name="good"></param>
        /// <returns></returns>
        public IMLDataPair CreateData(List<LoadedMarketData> data, int index, bool good)
        {
            BasicNeuralData ideal = new BasicNeuralData(1);

            INeuralData input = CreateData(data, index);

            if (input == null)
                return null;

            
            if (good)
                ideal[0] = 0.9;
            else
                ideal[0] = 0.1;

            return new BasicMLDataPair(input, ideal);
        }

  
        /// <summary>
        /// wczytuje dane trenigowe z serwisu Yahoo Finance.         /// 
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="training"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        public void LoadCompany(String symbol, BasicMLDataSet training, DateTime from, DateTime to)
        {
            IMarketLoader loader = new YahooFinanceLoader();
            TickerSymbol ticker = new TickerSymbol(symbol);
            IList<MarketDataType> dataNeeded = new List<MarketDataType>();


            // podanie danych, które mają być pobrane
            dataNeeded.Add(MarketDataType.AdjustedClose);
            dataNeeded.Add(MarketDataType.Close);
            dataNeeded.Add(MarketDataType.Open);
            dataNeeded.Add(MarketDataType.High);
            dataNeeded.Add(MarketDataType.Low);

            List<LoadedMarketData> results = null;
            try
            {
                results = (List<LoadedMarketData>)loader.Load(ticker, dataNeeded, from, to);
            }
            catch (Exception e)
            {
                MessageBox.Show("exception " + e.ToString());
                return;
            }

            results.Sort();

            for (int index = PredictWindow; index < results.Count - EvalWindow; index++)
            {
                LoadedMarketData data = results[index];

                // czy trend wzrostowy czy spadkowy
                bool bullish = false;
                bool bearish = false;

                for (int search = 1; search <= EvalWindow; search++)
                {
                    LoadedMarketData data2 = results[index + search];
                    double priceBase = data.GetData(MarketDataType.AdjustedClose);
                    double priceCompare = data2.GetData(MarketDataType.AdjustedClose);
                    double diff = priceCompare - priceBase;
                    double percent = diff / priceBase;

                    // czy przekracza przyjęte progi
                    if (percent > BullPercent)
                    {
                        bullish = true;
                    }
                    else if (percent < BearPercent)
                    {
                        bearish = true;
                    }
                }

                IMLDataPair pair = null;

                // jeśli wykryto trend, tworzymy parę treningową
                if (bullish)
                {
                    pair = CreateData(results, index, true);
                }
                else if (bearish)
                {
                    pair = CreateData(results, index, false);
                }

                if (pair != null)
                {
                    training.Add(pair);
                }
            }

            
        }
    }
}
